//==========================================================================
// Copyright (c) 2000-2008,  Elastos, Inc.  All Rights Reserved.
//==========================================================================

#include <ddk.h>
#include "rtl_8139.h"

//#define _RTL_DEBUG_

//
// Rtl8139Driver
//

class Rtl8139Driver : public CDeviceDriver {
public:
    CARAPI Read(
        /* [in] */ Int64 u64Offset,
        /* [in] */ Int32 bytesToRead,
        /* [out] */ MemoryBuf * pBuffer,
        /* [out] */ IEvent * * ppCompletionEvent);

    CARAPI Write(
        /* [in] */ Int64 u64Offset,
        /* [in] */ const MemoryBuf & buffer,
        /* [out] */ Int32 * pBytesWritten,
        /* [out] */ IEvent * * ppCompletionEvent);

    CARAPI Control(
        /* [in] */ Handle32 nControlCode,
        /* [in] */ const MemoryBuf & inBuffer,
        /* [out] */ MemoryBuf * pOutBuffer,
        /* [out] */ IEvent * * ppCompletionEvent);

    virtual void Dispose();

public:
};

extern "C" timeval tv1,tv2,tv3,tv4;
extern "C" void __cdecl getmicrotime(struct timeval* time);
ECode Rtl8139Driver::Read(
    /* [in] */ Int64 u64Offset,
    /* [in] */ Int32 bytesToRead,
    /* [out] */ MemoryBuf * pBuffer,
    /* [out] */ IEvent * * ppCompletionEvent)
{
    UInt32 addr = bytesToRead;
    RL_SOFTC* pRtl = (RL_SOFTC*)addr;
    struct queue * readbuf = (struct queue *)pRtl->readBuf;
    int ret;

    //if the queue is empty, wait here for data
    if (readbuf->tail == readbuf->head) {
        Wait(pRtl->pReadSignal, &ret);
        getmicrotime(&tv4);
    }
    return NOERROR;
}

ECode Rtl8139Driver::Write(
    /* [in] */ Int64 u64Offset,
    /* [in] */ const MemoryBuf & buffer,
    /* [out] */ Int32 * pBytesWritten,
    /* [out] */ IEvent * * ppCompletionEvent)
{
    RL_SOFTC* pRtl = (RL_SOFTC*)buffer.GetPayload();
    RTL8139Xmit(pRtl);

    return NOERROR;
}

struct ioctl_arg_t{
    union{
        void * pRtl;   //kernel mode data addr
        void * pIf;    //user mode data addr
    }io;
    UInt32 command;
};
#define io_Rtl io.pRtl
#define io_If  io.pIf



ECode Rtl8139Driver::Control(
    /* [in] */  Handle32 nControlCode,
    /* [in] */ const  MemoryBuf & inBuffer,
    /* [out] */ MemoryBuf * pOutBuffer,
    /* [out] */ IEvent * * ppCompletionEvent)
{
    struct ioctl_arg_t * arg = (struct ioctl_arg_t *)inBuffer.GetPayload();
    Rtl8139* pRtl;
    UInt32      cmd;
    RL_SOFTC* rl_sc;

#ifdef _RTL_DEBUG_
kprintf("\n&&&& (-)kernel Control  %d\n", __LINE__);
#endif

    switch (nControlCode) {
        case RTL8139INITALIZE:
            rl_sc = (RL_SOFTC*)arg->io_Rtl;

#ifdef _RTL_DEBUG_
kprintf("\n&&&& (-)kernel Control this %08x\n", rl_sc);
#endif

            RTL8139Initalize(rl_sc);
            break;
        case RTL8139IOCTL:

#ifdef _RTL_DEBUG_
kprintf("\n&&&& (-)kernel Control  %d\n", __LINE__);
#endif

            rl_sc = (RL_SOFTC*)arg->io_Rtl;
            cmd = arg->command;
            RTL8139Ioctl(rl_sc, cmd);
            break;
        case RTL8139WATCHDOG:

#ifdef _RTL_DEBUG_
kprintf("\n&&&& (-)kernel Control  %d\n", __LINE__);
#endif

            rl_sc = (RL_SOFTC*)arg->io_Rtl;
            RTL8139Watchdog(rl_sc);
            break;
        case RTL8139CONNECT:

#ifdef _RTL_DEBUG_
kprintf("\n&&&& (-)kernel Control  %d\n", __LINE__);
kprintf("kernel Connect queue = %08x\n", arg->command);
#endif

            pRtl = (Rtl8139*)arg->io_If;
            Rtl8139_Connect(&rl_sc, pRtl);
            if (pOutBuffer == NULL) {
                return E_INVALID_ARGUMENT;
            }
            pOutBuffer->Copy((Byte *)&(rl_sc), sizeof(int));
            rl_sc->readBuf = (char*)arg->command;
            //buf size
            rl_sc->size = ((struct queue*)(rl_sc->readBuf))->len;

#ifdef _RTL_DEBUG_
kprintf("\n connect kernel data addr %08x %08x %08x %8x\n", (UInt32*)pOutBuffer->GetPayload(),
                    rl_sc, &rl_sc, *(UInt32*)pOutBuffer->GetPayload());
#endif

            break;
        default:
            return EINVAL;
            break;
    }
    return NOERROR;
}

void Rtl8139Driver::Dispose()
{
    delete this;
}


void getdriverinfo(int * pirq, int * piobase);

EXTERN IDeviceDriver * CDECL CreateRtl8139(uint_t uDeviceNo, void *pvParameter)
{
    IDeviceDriver *pDriver;
    int irq, iobase;
    return NULL;
    getdriverinfo(&irq, &iobase);
    kprintf("irq = %d  iobase = %08x\n", irq, iobase);
    pDriver = new Rtl8139Driver();
    if (NULL == pDriver) return NULL;
    RTL8139New(&iobase, &irq, NULL);
    pDriver->AddRef();
    return pDriver;
}

